package com.example.security_demo.sms;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 自定义 手机验证码认证过滤器
 *
 * @author zzh
 * @date 2022/4/23
 * @since 1.0
 */
@Slf4j
public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private final ObjectMapper objectMapper = new ObjectMapper();

    private final static String SMS_MOBILE_KEY = "mobile";

    private final static String SMS_CODE_KEY = "smsCode";

    private final static AntPathRequestMatcher ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/sms/login");

    private final static String POST_REQUEST_METHOD = "POST";


    public SmsAuthenticationFilter() {
        super(ANT_PATH_REQUEST_MATCHER);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equalsIgnoreCase(POST_REQUEST_METHOD)) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        // 从请求体中获取 电话号码和验证码 request
        if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
            try {
                JsonNode jsonBody = objectMapper.readTree(request.getInputStream());
                String mobile = jsonBody.get(SMS_MOBILE_KEY).textValue();
                String smsCode = jsonBody.get(SMS_CODE_KEY).textValue();
                log.info("mobile is: {}, smsCode is: {}", mobile, smsCode);
                // 调用 AuthenticationManager 进行认证, 所以需要注入 AuthenticationManager 对象 通过父类的setAuthenticationManager 进行注入
                return getAuthenticationManager().authenticate(new SmsAuthenticationToken( mobile, smsCode));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}
